package com.clouddisk.web.controller.system;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.net.URLDecoder;
import com.clouddisk.common.annotation.Log;
import com.clouddisk.common.core.controller.BaseController;
import com.clouddisk.common.core.domain.R;
import com.clouddisk.common.core.domain.dto.file.BatchDownloadFileDTO;
import com.clouddisk.common.core.domain.dto.file.DownloadFileDTO;
import com.clouddisk.common.core.domain.dto.file.PreviewDTO;
import com.clouddisk.common.core.domain.dto.file.UploadFileDTO;
import com.clouddisk.common.core.domain.entity.FileBean;
import com.clouddisk.common.core.domain.entity.StorageBean;
import com.clouddisk.common.core.domain.entity.UserFile;
import com.clouddisk.common.enums.BusinessType;
import com.clouddisk.common.utils.FilesUtils;
import com.clouddisk.common.utils.MimeUtils;
import com.clouddisk.common.utils.SuffixUtils;
import com.clouddisk.oss.factory.OssUfoFactory;
import com.clouddisk.system.component.FileDealComp;
import com.clouddisk.system.domain.vo.file.UploadFileVo;
import com.clouddisk.system.service.IFileService;
import com.clouddisk.system.service.IFiletransferService;
import com.clouddisk.system.service.IStorageService;
import com.clouddisk.system.service.IUserFileService;
import com.qiwenshare.ufop.operation.download.Downloader;
import com.qiwenshare.ufop.operation.download.domain.DownloadFile;
import com.qiwenshare.ufop.operation.download.domain.Range;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户文件管理
 * 该接口为文件传输接口，主要用来做文件的上传、下载和预览
 *
 * @author ZJH
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/filetransfer")
public class SysFiletransferController extends BaseController {

    @Resource
    IFiletransferService filetransferService;

    @Resource
    IFileService fileService;
    @Resource
    IUserFileService userFileService;
    @Resource
    FileDealComp fileDealComp;
    @Resource
    IStorageService storageService;
    @Resource
    OssUfoFactory ossUfoFactory;

    @RequestMapping(value = "/uploadfile", method = RequestMethod.GET)
    @ResponseBody
    public R<UploadFileVo> uploadFileSpeed(HttpServletRequest request,UploadFileDTO uploadFileDto) throws UnsupportedEncodingException {
        String fileDeptName = URLDecoder.decode(request.getHeader("filedeptname"), StandardCharsets.UTF_8);
        // 看fileDeptName是否为个人，如果不是需要查的是组织的空间内存
        boolean isCheckSuccess = storageService.checkStorage(getUserId(), uploadFileDto.getTotalSize(), fileDeptName);
        if (!isCheckSuccess) {
            return R.fail("存储空间不足");
        }
        UploadFileVo uploadFileVo = filetransferService.uploadFileSpeed(uploadFileDto,getUserId(),fileDeptName);
        return R.ok(uploadFileVo);
    }

    @Log(title = "文件上传", businessType = BusinessType.IMPORT)
    @RequestMapping(value = "/uploadfile", method = RequestMethod.POST)
    @ResponseBody
    public R<UploadFileVo> uploadFile(HttpServletRequest request, UploadFileDTO uploadFileDto) {
        filetransferService.uploadFile(request, uploadFileDto, getUserId());
        UploadFileVo uploadFileVo = new UploadFileVo();
        return R.ok(uploadFileVo);
    }

    @Log(title = "文件下载", businessType = BusinessType.EXPORT)
    @RequestMapping(value = "/downloadfile", method = RequestMethod.GET)
    public void downloadFile(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, DownloadFileDTO downloadFileDTO) {
        boolean authResult = fileDealComp.checkAuthDownloadAndPreview(downloadFileDTO.getShareBatchNum(),
            downloadFileDTO.getExtractionCode(),
            downloadFileDTO.getUserFileId(), null);
        if (!authResult) {
            // log.error("没有权限下载！！！");
            return;
        }
        httpServletResponse.setContentType("application/force-download");// 设置强制下载不打开
        UserFile userFile = userFileService.getById(downloadFileDTO.getUserFileId());
        String fileName = "";
        if (userFile.getIsDir() == 1) {
            fileName = userFile.getFileName() + ".zip";
        } else {
            fileName = userFile.getFileName() + "." + userFile.getExtendName();

        }
        fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        httpServletResponse.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名
        filetransferService.downloadFile(httpServletResponse, downloadFileDTO);
    }

    @Log(title = "文件批量下载", businessType = BusinessType.EXPORT)
    @RequestMapping(value = "/batchDownloadFile", method = RequestMethod.GET)
    @ResponseBody
    public void batchDownloadFile(HttpServletResponse httpServletResponse, BatchDownloadFileDTO batchDownloadFileDTO) {
        String files = batchDownloadFileDTO.getUserFileIds();
        String[] userFileIdStrs = files.split(",");
        List<String> userFileIds = new ArrayList<>();
        for(String userFileId : userFileIdStrs) {
            UserFile userFile = userFileService.getById(userFileId);
            if (userFile.getIsDir() == 0) {
                userFileIds.add(userFileId);
            } else {
                FilesUtils filesUtils = new FilesUtils(userFile.getFilePath(), userFile.getFileName(), true);
                List<UserFile> userFileList = userFileService.selectUserFileByLikeRightFilePath(filesUtils.getPath(), userFile.getUserId(),userFile.getFileDeptName());
                List<String> userFileIds1 = userFileList.stream().map(UserFile::getUserFileId).collect(Collectors.toList());
                userFileIds.add(userFile.getUserFileId());
                userFileIds.addAll(userFileIds1);
            }
        }
        UserFile userFile = userFileService.getById(userFileIdStrs[0]);
        httpServletResponse.setContentType("application/force-download");// 设置强制下载不打开
        Date date = new Date();
        String fileName = String.valueOf(date.getTime());
        httpServletResponse.addHeader("Content-Disposition", "attachment;fileName=" + fileName + ".zip");// 设置文件名
        filetransferService.downloadUserFileList(httpServletResponse, userFile.getFilePath(), fileName, userFileIds);
    }

    @SaIgnore
    @GetMapping("/preview")
    public void preview(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,  PreviewDTO previewDTO) throws IOException {
        if (previewDTO.getPlatform() != null && previewDTO.getPlatform() == 2) {
            filetransferService.previewPictureFile(httpServletResponse, previewDTO);
            return ;
        }
        UserFile userFile = userFileService.getById(previewDTO.getUserFileId());
        boolean authResult = fileDealComp.checkAuthDownloadAndPreview(previewDTO.getShareBatchNum(),
            previewDTO.getExtractionCode(),
            previewDTO.getUserFileId(),
            previewDTO.getPlatform());

        if (!authResult) {
            // log.error("没有权限预览！！！");
            return;
        }
        String fileName = userFile.getFileName() + "." + userFile.getExtendName();
        fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        httpServletResponse.addHeader("Content-Disposition", "fileName=" + fileName);// 设置文件名
        String mime = MimeUtils.getMime(userFile.getExtendName());
        httpServletResponse.setHeader("Content-Type", mime);
        FileBean fileBean = fileService.getById(userFile.getFileId());
        if ((SuffixUtils.isVideoFile(userFile.getExtendName()) || "mp3".equalsIgnoreCase(userFile.getExtendName()) || "flac".equalsIgnoreCase(userFile.getExtendName()))
            && !"true".equals(previewDTO.getIsMin())) {
            //获取从那个字节开始读取文件
            String rangeString = httpServletRequest.getHeader("Range");
            int start = 0;
            if (StringUtils.isNotBlank(rangeString)) {
                start = Integer.parseInt(rangeString.substring(rangeString.indexOf("=") + 1, rangeString.indexOf("-")));
            }
            Downloader downloader = ossUfoFactory.getDownloader(fileBean.getStorageType());
            DownloadFile downloadFile = new DownloadFile();
            downloadFile.setFileUrl(fileBean.getFileUrl());
            Range range = new Range();
            range.setStart(start);
            range.setLength(1024 * 1024);
            downloadFile.setRange(range);
            InputStream inputStream = downloader.getInputStream(downloadFile);
            OutputStream outputStream = httpServletResponse.getOutputStream();
            try {
                //返回码需要为206，代表只处理了部分请求，响应了部分数据
                httpServletResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                // 每次请求只返回1MB的视频流
                httpServletResponse.setHeader("Accept-Ranges", "bytes");
                //设置此次相应返回的数据范围
                httpServletResponse.setHeader("Content-Range", "bytes " + start + "-" + (fileBean.getFileSize() - 1) + "/" + fileBean.getFileSize());
                IOUtils.copy(inputStream, outputStream);
            } finally {
                IOUtils.closeQuietly(inputStream);
                IOUtils.closeQuietly(outputStream);
                if (downloadFile.getOssClient() != null) {
                    downloadFile.getOssClient().shutdown();
                }
            }
        } else {
            filetransferService.previewFile(httpServletResponse, previewDTO);
        }
    }

    @RequestMapping(value = "/getstorage", method = RequestMethod.GET)
    @ResponseBody
    public R<StorageBean> getStorage(String fileDeptName) {
        StorageBean storageBean = new StorageBean();
        storageBean.setUserId(getUserId());
        Long storageSize = filetransferService.selectStorageSizeByUserId(getUserId(),fileDeptName);
        StorageBean storage = new StorageBean();
        storage.setUserId(getUserId());
        storage.setStorageSize(storageSize);
        Long totalStorageSize = storageService.getTotalStorageSize(getUserId(), fileDeptName);
        storage.setTotalStorageSize(totalStorageSize);
        return R.ok(storage);

    }
}
